package ar.uade.edu.fain.ad.server.dao.jpa;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.PersistenceException;

import org.hibernate.Session;

import ar.uade.edu.fain.ad.server.business.Caja;
import ar.uade.edu.fain.ad.server.business.Factura;
import ar.uade.edu.fain.ad.server.business.ItemFactura;
import ar.uade.edu.fain.ad.server.business.MedioPago;
import ar.uade.edu.fain.ad.server.business.Pedido;
import ar.uade.edu.fain.ad.server.business.Plato;
import ar.uade.edu.fain.ad.server.dao.CajaDAO;
import ar.uade.edu.fain.ad.server.dao.FacturaDAO;
import ar.uade.edu.fain.ad.server.dao.PedidoDAO;
import ar.uade.edu.fain.ad.server.dao.PlatoDAO;
import ar.uade.edu.fain.ad.server.dao.entity.CajaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.FacturaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.ItemFacturaEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MedioPagoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.MozoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.PedidoEntity;
import ar.uade.edu.fain.ad.server.dao.entity.PlatoEntity;
import ar.uade.edu.fain.ad.server.util.DateUtils;

public class FacturaJpaDAO 
		extends GenericJpaDAO<Factura, FacturaEntity, Long>
		implements FacturaDAO {

	private CajaDAO cajaDAO;
	
	private PlatoDAO platoDAO;
	
	private PedidoDAO pedidoDAO;
	
	public FacturaJpaDAO() {
		super(FacturaEntity.class);
	}

	public CajaDAO getCajaDAO() {
		return cajaDAO;
	}

	public void setCajaDAO(CajaDAO cajaDAO) {
		this.cajaDAO = cajaDAO;
	}

	public PlatoDAO getPlatoDAO() {
		return platoDAO;
	}

	public void setPlatoDAO(PlatoDAO platoDAO) {
		this.platoDAO = platoDAO;
	}

	public PedidoDAO getPedidoDAO() {
		return pedidoDAO;
	}

	public void setPedidoDAO(PedidoDAO pedidoDAO) {
		this.pedidoDAO = pedidoDAO;
	}

	@Override
	protected FacturaEntity toEntity(Factura business) {
		final Session session = getSession();
		final FacturaEntity entity;
		if (business.getId() == null) {
			entity = new FacturaEntity();
			entity.setPedidos(new HashSet<PedidoEntity>());
			entity.setItems(new ArrayList<ItemFacturaEntity>());
			for (Pedido pedido : business.getPedidos()) {
				final PedidoEntity pedidoEntity = (PedidoEntity) 
						session.get(PedidoEntity.class, pedido.getId());
				pedidoEntity.setFactura(entity);
				entity.getPedidos().add(pedidoEntity);
			}
			for (ItemFactura itemFactura : business.getItems()) {
				ItemFacturaEntity itemFacturaEntity = new ItemFacturaEntity();
				itemFacturaEntity.setCantidad(itemFactura.getCantidad());
				itemFacturaEntity.setPlatoFacturado((PlatoEntity) 
						session.get(PlatoEntity.class, 
								itemFactura.getPlatoFacturado().getId()));
				entity.getItems().add(itemFacturaEntity);
			}
		} else {
			entity = (FacturaEntity) 
					session.get(FacturaEntity.class, business.getId());
		}
		entity.setFecha(business.getFecha());
		entity.setTotal(business.getTotal());
		final MedioPago medioPago = business.getMedioPago();
		if (medioPago != null) {
			entity.setMedioPago((MedioPagoEntity) session.get(
					MedioPagoEntity.class, medioPago.getId()));
		} else {
			entity.setMedioPago(null);
		}
		final Caja caja = business.getCaja();
		if (caja != null) {
			final CajaEntity cajaEntity = 
					(CajaEntity) session.get(CajaEntity.class, caja.getId());
			entity.setCaja(cajaEntity);
		}
		return entity;
	}

	@Override
	protected Factura toBusiness(final FacturaEntity entity) {
		final Factura business = new Factura();
		business.setId(entity.getId());
		business.setFecha(entity.getFecha());
		business.setTotal(entity.getTotal());
		final MedioPagoEntity medioPagoEntity = entity.getMedioPago();
		if (medioPagoEntity != null) {
			final MedioPago medioPago = new MedioPago();
			medioPago.setId(medioPagoEntity.getId());
			business.setMedioPago(medioPago);
		}
		final Caja caja = getCajaDAO().get(entity.getCaja().getId());
		business.setCaja(caja);
		for (ItemFacturaEntity itemFacturaEntity : entity.getItems()) {
			final ItemFactura itemFactura = new ItemFactura();
			itemFactura.setCantidad(itemFacturaEntity.getCantidad());
			itemFactura.setId(itemFacturaEntity.getId());
			final PlatoEntity platoEntity = 
					itemFacturaEntity.getPlatoFacturado();
			final Plato plato = getPlatoDAO().get(platoEntity.getId());
			itemFactura.setPlatoFacturado(plato);
			business.getItems().add(itemFactura);
		}
		for (PedidoEntity pedidoEntity : entity.getPedidos()) {
			final Pedido pedido = getPedidoDAO().get(pedidoEntity.getId());
			final MozoEntity mozoEntity = 
					(MozoEntity) getSession().get(
							MozoEntity.class, pedido.getMozo().getId());
			pedido.getMozo().setPorcentajeBase(mozoEntity.getPorcentajeBase());
			business.getPedidos().add(pedido);
		}
		return business;
	}

	@Override
	public Set<Factura> buscarFacturas(
			final Long idCaja, final Date fechaEmision) {
		return execute(new Query<Set<Factura>>() {
			@Override
			public Set<Factura> inTransaction(final Session session)
					throws PersistenceException {
				@SuppressWarnings("unchecked")
				final List<FacturaEntity> entities = 
						session.getNamedQuery("factura.byCajaByDate")
								.setParameter("idCaja", idCaja)
								.setParameter("fecha",  
										limpiarTimeDe(fechaEmision))
								.list();
				final List<Factura> business = toBusiness(entities);
				return new HashSet<Factura>(business);
			}
		});
	}

	@Override
	public Double sumarTotalCon(
			final Long idCaja, final String tipoMedioPago, final Date fechaEmision) {
		return execute(new Query<Double>() {
			@Override
			public Double inTransaction(final Session session)
					throws PersistenceException {
				final Double total = (Double) session
								.getNamedQuery("factura.sumarTotalByMedioPago")
								.setParameter("idCaja", idCaja)
								.setParameter("tipoMedioPago", tipoMedioPago)
								.setParameter("fecha",  limpiarTimeDe(fechaEmision))
								.uniqueResult();
				return total == null ? 0D : total;
			}
		});
	}

	private Date limpiarTimeDe(final Date fechaEmision) {
		return DateUtils.limpiarHora(fechaEmision);
	}
	
}
